package com.jk.lucense;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * Lucene索引读写器/查询器单例获取工具类
 *
 * @author 缪隽峰
 * @version 1.0
 * @date 2016年11月24日
 */
@Slf4j
@Data
public class LuceneManager {
    private volatile static LuceneManager singleton;

    private volatile static IndexWriter writer;

    private volatile static IndexReader reader;

    private volatile static IndexSearcher searcher;

    private final Lock writerLock = new ReentrantLock();

    private final Lock readerLock = new ReentrantLock();

    private final Lock searcherLock = new ReentrantLock();

    private LuceneManager() {
    }

    public static LuceneManager getInstance() {
        if (null == singleton) {
            synchronized (LuceneManager.class) {
                if (null == singleton) {
                    singleton = new LuceneManager();
                }
            }
        }
        return singleton;
    }

    /**
     * 获取IndexWriter单例对象
     *
     * @param dir
     * @param config
     * @return
     */
    public IndexWriter getIndexWriter(Directory dir, IndexWriterConfig config) {
        if (null == dir) {
            throw new IllegalArgumentException("Directory can not be null.");
        }
        if (null == config) {
            throw new IllegalArgumentException(
                    "IndexWriterConfig can not be null.");
        }
        try {
            writerLock.lock();
            if (null == writer || !writer.isOpen()) {
                // 如果索引目录被锁，则直接抛异常l.
                if (IndexWriter.isLocked(dir)) {
                    throw new LockObtainFailedException(
                            "Directory of index had been locked.");
                }
                writer = new IndexWriter(dir, config);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            writerLock.unlock();
        }
        return writer;
    }

    /**
     * 获取IndexReader对象
     *
     * @param dir
     * @param enableNRTReader 是否开启NRTReader
     * @return IndexReader
     */
    public IndexReader getIndexReader(Directory dir, boolean enableNRTReader) {
        if (null == dir) {
            throw new IllegalArgumentException("Directory can not be null.");
        }
        try {
            if (null == reader) {
                reader = DirectoryReader.open(dir);
            } else {
                if (enableNRTReader && reader instanceof DirectoryReader) {
                    // 开启近实时Reader,能立即看到动态添加/删除的索引变化
                    reader = DirectoryReader.openIfChanged((DirectoryReader) reader);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return reader;
    }


    /**
     * 获取IndexSearcher对象
     *
     * @param reader   IndexReader对象实例
     * @param executor 如果你需要开启多线程查询，请提供ExecutorService对象参数
     * @return IndexSearcher
     */
    public IndexSearcher getIndexSearcher(IndexReader reader, ExecutorService executor) {
        if (null == reader) {
            throw new IllegalArgumentException(
                    "The indexReader can not be null.");
        }
        if (null == searcher) {
            searcher = new IndexSearcher(reader);
        }
        return searcher;
    }

    /**
     * 获取IndexSearcher对象(不支持多线程查询)
     *
     * @param reader IndexReader对象实例
     * @return IndexSearcher
     */
    public IndexSearcher getIndexSearcher(IndexReader reader) {
        return getIndexSearcher(reader, null);
    }
}